<?php


namespace App\Helpers\utils\WeChat;


use App\Helpers\HttpClass;
use App\Models\Setting;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;

class OfficialAccount
{
    var $url = 'https://api.weixin.qq.com/cgi-bin/';
    /**
     * 验证微信公众平台的token
     * @param $signature
     * @param $timestamp
     * @param $nonce
     * @param $echoStr
     * @param $token
     * @return mixed
     */
    public function checkToken($signature, $timestamp, $nonce, $echoStr, $token) {
        $result = $this->getSHA1($timestamp, $nonce, $token);
        if ($signature == $result)
        {
            return $echoStr;
        }
        else
        {
            return 'error';
        }
    }

    /**
     * 文本消息
     * @param $data
     * @return array
     */
    public function textMsg($data) {
        return array(
            'ToUserName' => $data['FromUserName'],
            'FromUserName' => $data['ToUserName'],
            'CreateTime' => $data['CreateTime'],
            'MsgType' => 'text',
            'Content' => $data['Reply']
        );
    }

    /**
     * 图文消息
     * @param $data: 发送消息的基本数据，如发送给谁
     * @param $items: (array) 图文的具体数据，数组元素为 array，包含：Title, Description, PicUrl, Url
     * @return array
     */
    public function articleMsg($data, $items) {
        // 限制文章数量不能超过8
        $items = array_slice($items, 0, 7);
        $articles = [];
        foreach ($items as $key => $item) {
            $article = [
                'Title' => $item['Title'],
                'Description' => $item['Description'],
                'PicUrl' => $item['PicUrl'],
                'Url' => $item['Url'],
            ];
            $articles['item' . $key] = $article;
        }
        return array(
            'ToUserName' => $data['FromUserName'],
            'FromUserName' => $data['ToUserName'],
            'CreateTime' => $data['CreateTime'],
            'MsgType' => 'news',
            'ArticleCount' => count($items),
            'Articles' => $articles,
        );
    }

    /**
     * 获取access_token(全局)
     * @return \Illuminate\Http\Client\Response
     */
    public function getAccessToken() {
        $setting = Setting::where('key', 'app_id')->first();
        $appId = $setting['value'];
        $setting = Setting::where('key', 'app_secret')->first();
        $appSecret = $setting['value'];
        $url = $this->url . 'token?grant_type=client_credential&appid=' .
            $appId . '&secret=' . $appSecret;
        return Http::get($url);
    }

    /**
     * 根据openid获取用户信息
     * @param $openid
     * @return \Illuminate\Http\Client\Response
     */
    public function getUserInfoByOpenid($openid) {
        $token = checkSetting('access_token');
        $url = $this->url . 'user/info?access_token=' . $token . '&openid=' . $openid . '&lang=zh_CN';
        return Http::get($url);
    }

    /**
     * 用SHA1算法生成安全签名
     * @param $timestamp : 时间戳
     * @param $nonce : 随机字符串
     * @param $token : 公众号Token
     * @return string
     */
    private function getSHA1($timestamp, $nonce, $token) {
        // 排序
        $array = array($token, $timestamp, $nonce);
        sort($array, SORT_STRING);
        $str = implode($array);
        return sha1($str);
    }

    /**
     * 把对象转换成数组.
     * @param string $data: 数据
     * @return array
     */
    public function objToArr($data) {
        if (is_object($data) && get_class($data) === 'SimpleXMLElement')
        {
            $data = (array) $data;
        }
        if (is_array($data))
        {
            foreach ($data as $index => $value)
            {
                $data[$index] = $this->objToArr($value);
            }
        }
        return $data;
    }

    /**
     * 将数据封装成能返回的xml格式
     * @param $data
     * @return string
     */
    public function responseXml($data) {
        $data = '<xml>' . $this->arrToXml($data) . '</xml>';
        // 以下处理为了兼容图文消息的文章列表
        $data = str_replace('item0', 'item', $data);
        $data = str_replace('item1', 'item', $data);
        $data = str_replace('item2', 'item', $data);
        $data = str_replace('item3', 'item', $data);
        $data = str_replace('item4', 'item', $data);
        $data = str_replace('item5', 'item', $data);
        $data = str_replace('item6', 'item', $data);
        $data = str_replace('item7', 'item', $data);
        $data = str_replace('item8', 'item', $data);
        return $data;
    }

    /**
     * 转换数组为xml.
     *
     * @param array  $data 数组
     * @param string $item item的属性名
     * @param string $id   id的属性名
     *
     * @return string
     */
    private function arrToXml($data, $item='item', $id='id') {
        if (empty($data)) {
            return '';
        }
        $xml = $attr = '';
        foreach ($data as $key => $val)
        {
            if (is_numeric($key))
            {
                $id && $attr = " {$id}=\"{$key}\"";
                $key = $item;
            }
            $xml .= "<{$key}{$attr}>";
            if ((is_array($val) || is_object($val)))
            {
                $xml .= $this->arrToXml((array) $val, $item, $id);
            }
            else
            {
                $xml .= is_numeric($val) ? $val : $this->cData($val);
            }
            $xml .= "</{$key}>";
        }
        return $xml;
    }

    /**
     * 生成<![CDATA[%s]]>.
     *
     * @param string $string 内容
     *
     * @return string
     */
    private function cData($string) {
        return sprintf('<![CDATA[%s]]>', $string);
    }

    /**
     * 获取永久素材
     * @param string $type 素材类型
     * @param int $offset 0表示从第一个素材
     * @param int $count 返回素材的数量，取值在1到20之间
     * @return mixed
     */
    public function getMaterial($type = 'news', $offset = 0, $count = 10) {
        $accessToken = checkSetting('access_token');
        $url = $this->url . 'material/batchget_material?access_token=' . $accessToken;
        // $params = '{
        //     "type": "' . $type . '",
        //     "offset": ' . $offset . ',
        //     "count": ' . $count . ',
        // }';
        $params = [
            'type' => $type,
            'offset' => $offset,
            'count' => $count
        ];
        return Http::post($url, $params);
    }

    /**
     * 图片消息
     * @param $data
     * @return array
     */
    public function imageMsg($data) {
        return array(
            'ToUserName' => $data['FromUserName'],
            'FromUserName' => $data['ToUserName'],
            'CreateTime' => $data['CreateTime'],
            'MsgType' => 'image',
            'MediaId' => '9kiaD1a1hYiaSGGFndwhafFFib7FZ0MyWMrxCviauriajpjJmrHZQRJbLtbxlSXSwTSXGH1CMnzqKY8FhuUibibt9jI8Q/0'
        );
    }

    /**
     * 获取公众号菜单数据
     * @return \Illuminate\Http\Client\Response
     */
    public function menuList() {
        $token = checkSetting('access_token');
        $url = $this->url . 'menu/get?access_token=' . $token;
        return Http::get($url);
    }

    /**
     * 创建公众号菜单
     * @param $menus
     * @return mixed
     */
    public function menuCreate($menus) {
        $menus = json_encode($menus, JSON_UNESCAPED_UNICODE);
        $token = checkSetting('access_token');
        $url = $this->url . 'menu/create?access_token=' . $token;
        $ajax = new HttpClass();
        return $ajax->post($url, $menus);
    }

    public function menuQuery() {
        $token = checkSetting('access_token');
        $url = $this->url . 'get_current_selfmenu_info?access_token=' . $token;
        return Http::get($url);
    }

    public function menuDelete() {
        $token = checkSetting('access_token');
        $url = $this->url . 'menu/delete?access_token=' . $token;
        return Http::get($url);
    }

    /**
     * 获取用户列表
     * @param $openid : 第一个拉取的用户openid
     * @return mixed
     */
    public function getUserList($openid='') {
        $accessToken = checkSetting('access_token');
        $url = $this->url . 'user/get?access_token=' . $accessToken . '&next_openid=' .
            $openid;
        $result = Http::get($url);
        return $result;
    }

    /**
     * 公众号用于调用微信JS接口的临时票据
     * @return mixed
     */
    public function getJsApiTicket() {
        $accessToken = checkSetting('access_token');
        $url = $this->url . 'ticket/getticket?access_token=' . $accessToken . '&type=jsapi';
        $result = Http::get($url);
        return $result;
    }
}
